package com.ruoyi.collect.engine.transformer;

import com.ruoyi.collect.domain.CollectBind;
import com.ruoyi.collect.domain.CollectTask;
import com.ruoyi.collect.engine.client.MacCmsResponse;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.movie.domain.MovieBasics;
import com.ruoyi.movie.domain.VideoResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * Data transformer
 * Convert MacCMS vod data to local MovieBasics and VideoResource
 *
 * @author ruoyi
 * @date 2025-11-07
 */
@Component
public class DataTransformer {

    private static final Logger log = LoggerFactory.getLogger(DataTransformer.class);

    /**
     * Transform vod info to MovieBasics
     *
     * @param vod MacCMS vod info
     * @param task collect task
     * @param bindMap type binding map
     * @return MovieBasics object
     */
    public MovieBasics transformToMovieBasics(MacCmsResponse.VodInfo vod, CollectTask task, Map<String, CollectBind> bindMap) {
        MovieBasics movie = new MovieBasics();

        // Basic info
        movie.setTitle(vod.getVodName());
        movie.setSummary(vod.getVodContent());
        movie.setPoster(vod.getVodPic());
        movie.setRemark(vod.getVodRemarks());

        // 转换 vod_time 字符串为 Date 类型
        if (StringUtils.isNotEmpty(vod.getVodTime())) {
            try {
                // MacCMS vod_time 通常是 Unix 时间戳（秒）
                long timestamp = Long.parseLong(vod.getVodTime());
                movie.setPubDate(new Date(timestamp * 1000)); // 转换为毫秒
            } catch (NumberFormatException e) {
                // 如果不是时间戳，尝试作为日期字符串解析
                try {
                    movie.setPubDate(DateUtils.parseDate(vod.getVodTime()));
                } catch (Exception ex) {
                    log.debug("Cannot parse vod_time: {}", vod.getVodTime());
                }
            }
        }
        // Phase 5 新字段: 副标题
        movie.setSubTitle(vod.getVodSub());

        // Phase 5 新字段: 首字母 (自动提取首字符)
        if (StringUtils.isNotEmpty(vod.getVodLetter())) {
            movie.setLetter(vod.getVodLetter().substring(0, 1).toUpperCase());
        } else if (StringUtils.isNotEmpty(vod.getVodName())) {
            // 如果源数据没有letter,从标题提取首字符
            movie.setLetter(vod.getVodName().substring(0, 1).toUpperCase());
        }

        // Phase 5 新字段: 多图片字段
        movie.setPicThumb(vod.getVodPicThumb());
        movie.setPicSlide(vod.getVodPicSlide());
        movie.setPicScreenshot(vod.getVodPicScreenshot());

        // Phase 5 新字段: 扩展分类
        movie.setClassExtend(vod.getVodClass());

        // 新增字段映射: 英文名
        movie.setTitleEn(vod.getVodEn());

        // 新增字段映射: 标签
        movie.setTags(vod.getVodTag());

        // 新增字段映射: 版本
        movie.setVersions(vod.getVodVersion());

        // 新增字段映射: 时长
        movie.setDuration(vod.getVodDuration());

        // Additional info from MacCMS
        movie.setArea(vod.getVodArea());
        movie.setLanguages(vod.getVodLang());  // Use languages instead of language
        if (StringUtils.isNotEmpty(vod.getVodYear())) {
            try {
                movie.setYear(Integer.parseInt(vod.getVodYear()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse year: {}", vod.getVodYear());
            }
        }
        movie.setActorText(vod.getVodActor());
        movie.setDirectorText(vod.getVodDirector());

        // 新增字段映射: 编剧
        movie.setWriterText(vod.getVodWriter());

        // 新增字段映射: 制片人
        movie.setProducerText(vod.getVodProducer());

        // 新增字段映射: 简介/推荐语
        movie.setBlurb(vod.getVodBlurb());

        // 新增字段映射: 状态(正片/预告等)
        movie.setState(vod.getVodState());

        // 新增字段映射: 更新星期
        movie.setWeekday(vod.getVodWeekday());

        // 新增字段映射: 豆瓣ID
        if (StringUtils.isNotEmpty(vod.getVodDoubanId())) {
            try {
                movie.setDoubanId(Integer.parseInt(vod.getVodDoubanId()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse douban ID: {}", vod.getVodDoubanId());
            }
        }

        // 新增字段映射: MacCMS评分
        if (StringUtils.isNotEmpty(vod.getVodScore())) {
            try {
                movie.setVodScore(Double.parseDouble(vod.getVodScore()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse vod score: {}", vod.getVodScore());
            }
        }

        // 新增字段映射: 总评分
        if (StringUtils.isNotEmpty(vod.getVodScoreAll())) {
            try {
                movie.setVodScoreAll(Integer.parseInt(vod.getVodScoreAll()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse vod score all: {}", vod.getVodScoreAll());
            }
        }

        // 新增字段映射: 评分人数
        if (StringUtils.isNotEmpty(vod.getVodScoreNum())) {
            try {
                movie.setVodScoreNum(Integer.parseInt(vod.getVodScoreNum()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse vod score num: {}", vod.getVodScoreNum());
            }
        }

        // Collect tracking fields - use siteFlag for consistent deduplication
        // 确保这两个字段不为null，用于数据清理功能
        movie.setCollectFrom(StringUtils.isNotEmpty(task.getSiteFlag()) ? task.getSiteFlag() : "");
        movie.setCollectId(StringUtils.isNotEmpty(vod.getVodId()) ? vod.getVodId() : "");

        // Type mapping
        String typeId = vod.getTypeId();
        if (StringUtils.isNotEmpty(typeId) && bindMap.containsKey(typeId)) {
            CollectBind bind = bindMap.get(typeId);
            movie.setColumnValue(bind.getLocalTypeId().toString());
        } else {
            // Default column value
            movie.setColumnValue("movie");
        }

        // Episode info
        if (StringUtils.isNotEmpty(vod.getVodSerial())) {
            try {
                movie.setCurrentEpisode(Integer.parseInt(vod.getVodSerial()));
            } catch (NumberFormatException e) {
                log.debug("Cannot parse serial number: {}", vod.getVodSerial());
            }
        }

        if (StringUtils.isNotEmpty(vod.getVodTotal())) {
            try {
                movie.setTotalEpisodes(Integer.parseInt(vod.getVodTotal()));
            } catch (NumberFormatException e) {
                // Try to extract number from text like "完结" or "更新至10集"
                String totalStr = vod.getVodTotal().replaceAll("[^0-9]", "");
                if (StringUtils.isNotEmpty(totalStr)) {
                    try {
                        movie.setTotalEpisodes(Integer.parseInt(totalStr));
                    } catch (NumberFormatException ex) {
                        log.debug("Cannot parse total episodes: {}", vod.getVodTotal());
                    }
                }
            }
        }

        // Set status based on serial/total
        if (movie.getTotalEpisodes() != null && movie.getCurrentEpisode() != null) {
            if (movie.getCurrentEpisode().equals(movie.getTotalEpisodes())) {
                movie.setStatus("1"); // Completed
            } else {
                movie.setStatus("0"); // Ongoing
            }
        } else {
            movie.setStatus("0"); // Default to ongoing
        }

        // Timestamps
        movie.setCreateTime(DateUtils.getNowDate());
        movie.setUpdateTime(DateUtils.getNowDate());

        return movie;
    }

    /**
     * Transform play URLs to VideoResource list
     *
     * @param vod MacCMS vod info
     * @param movieId local movie ID
     * @return VideoResource list
     */
    public List<VideoResource> transformToVideoResources(MacCmsResponse.VodInfo vod, Integer movieId) {
        List<VideoResource> resources = new ArrayList<>();

        if (StringUtils.isEmpty(vod.getVodPlayFrom()) || StringUtils.isEmpty(vod.getVodPlayUrl())) {
            return resources;
        }

        // Split play sources
        String[] playFroms = vod.getVodPlayFrom().split("\\$\\$\\$");
        String[] playUrls = vod.getVodPlayUrl().split("\\$\\$\\$");

        // Phase 5 新字段: 播放服务器和备注 (可选)
        String[] playServers = null;
        String[] playNotes = null;

        if (StringUtils.isNotEmpty(vod.getVodPlayServer())) {
            playServers = vod.getVodPlayServer().split("\\$\\$\\$");
        }
        if (StringUtils.isNotEmpty(vod.getVodPlayNote())) {
            playNotes = vod.getVodPlayNote().split("\\$\\$\\$");
        }

        if (playFroms.length != playUrls.length) {
            log.warn("Play from and play URL count mismatch: {} vs {}", playFroms.length, playUrls.length);
            return resources;
        }

        // Process each play source
        for (int i = 0; i < playFroms.length; i++) {
            String playFrom = playFroms[i];
            String playUrl = playUrls[i];
            String playServer = (playServers != null && i < playServers.length) ? playServers[i] : null;
            String playNote = (playNotes != null && i < playNotes.length) ? playNotes[i] : null;

            if (StringUtils.isEmpty(playUrl)) {
                continue;
            }

            // Parse episodes
            String[] episodes = playUrl.split("#");
            for (String episode : episodes) {
                if (StringUtils.isEmpty(episode)) {
                    continue;
                }

                VideoResource resource = new VideoResource();
                resource.setMovieId(movieId);
                resource.setResources(playFrom); // Player source

                // Phase 5 新字段: 播放来源相关
                resource.setPlayFrom(playFrom);        // 播放来源标识 (youku/qq/iqiyi等)
                resource.setPlayServer(playServer);    // 播放服务器地址
                resource.setPlayNote(playNote);        // 播放备注信息

                // Parse episode format: "第1集$http://xxx.m3u8"
                String[] parts = episode.split("\\$");
                if (parts.length >= 2) {
                    resource.setTitle(parts[0]);
                    resource.setUrl(parts[1]);
                } else {
                    resource.setTitle("Episode");
                    resource.setUrl(episode);
                }

                resource.setCreateTime(DateUtils.getNowDate());
                resource.setUpdateTime(DateUtils.getNowDate());

                resources.add(resource);
            }
        }

        return resources;
    }

    /**
     * Check if movie needs update
     *
     * @param existing existing movie
     * @param vod new vod data
     * @param uprule update rule
     * @return true if needs update
     */
    public boolean needsUpdate(MovieBasics existing, MacCmsResponse.VodInfo vod, String uprule) {
        if (existing == null) {
            return true;
        }

        // Parse update rule
        // Format: ,a=append ,b=overwrite ,c=merge ,d=skip
        if (StringUtils.isEmpty(uprule)) {
            uprule = ",a"; // Default to append
        }

        String[] rules = uprule.split(",");
        for (String rule : rules) {
            if (StringUtils.isEmpty(rule)) {
                continue;
            }

            if (rule.startsWith("d")) {
                // Skip if exists
                return false;
            }

            if (rule.startsWith("a")) {
                // Append new episodes
                Integer currentEpisode = existing.getCurrentEpisode();
                if (currentEpisode != null && StringUtils.isNotEmpty(vod.getVodSerial())) {
                    try {
                        int newEpisode = Integer.parseInt(vod.getVodSerial());
                        if (newEpisode > currentEpisode) {
                            return true;
                        }
                    } catch (NumberFormatException e) {
                        // Ignore
                    }
                }
            }

            if (rule.startsWith("b")) {
                // Always overwrite
                return true;
            }

            if (rule.startsWith("c")) {
                // Merge: update if content changed
                if (!StringUtils.equals(existing.getRemark(), vod.getVodRemarks())) {
                    return true;
                }
                if (!StringUtils.equals(existing.getSummary(), vod.getVodContent())) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Merge movie data based on update rule
     *
     * @param existing existing movie
     * @param newMovie new movie data
     * @param uprule update rule
     */
    public void mergeMovieData(MovieBasics existing, MovieBasics newMovie, String uprule) {
        if (StringUtils.isEmpty(uprule)) {
            uprule = ",a"; // Default to append
        }

        String[] rules = uprule.split(",");
        for (String rule : rules) {
            if (StringUtils.isEmpty(rule)) {
                continue;
            }

            if (rule.startsWith("a")) {
                // Append: only update episode info
                existing.setCurrentEpisode(newMovie.getCurrentEpisode());
                existing.setTotalEpisodes(newMovie.getTotalEpisodes());
                existing.setStatus(newMovie.getStatus());
                existing.setRemark(newMovie.getRemark());
            }

            if (rule.startsWith("b")) {
                // Overwrite: update all fields
                existing.setTitle(newMovie.getTitle());
                existing.setSummary(newMovie.getSummary());
                existing.setPoster(newMovie.getPoster());
                existing.setRemark(newMovie.getRemark());
                existing.setArea(newMovie.getArea());
                existing.setLanguages(newMovie.getLanguages());
                if (newMovie.getYear() != null) {
                    existing.setYear(newMovie.getYear());
                }
                existing.setActorText(newMovie.getActorText());
                existing.setDirectorText(newMovie.getDirectorText());
                existing.setCurrentEpisode(newMovie.getCurrentEpisode());
                existing.setTotalEpisodes(newMovie.getTotalEpisodes());
                existing.setStatus(newMovie.getStatus());
            }

            if (rule.startsWith("c")) {
                // Merge: update non-empty fields
                if (StringUtils.isNotEmpty(newMovie.getTitle())) {
                    existing.setTitle(newMovie.getTitle());
                }
                if (StringUtils.isNotEmpty(newMovie.getSummary())) {
                    existing.setSummary(newMovie.getSummary());
                }
                if (StringUtils.isNotEmpty(newMovie.getPoster())) {
                    existing.setPoster(newMovie.getPoster());
                }
                if (StringUtils.isNotEmpty(newMovie.getRemark())) {
                    existing.setRemark(newMovie.getRemark());
                }
                if (StringUtils.isNotEmpty(newMovie.getArea())) {
                    existing.setArea(newMovie.getArea());
                }
                if (StringUtils.isNotEmpty(newMovie.getLanguages())) {
                    existing.setLanguages(newMovie.getLanguages());
                }
                if (newMovie.getYear() != null) {
                    existing.setYear(newMovie.getYear());
                }
                if (StringUtils.isNotEmpty(newMovie.getActorText())) {
                    existing.setActorText(newMovie.getActorText());
                }
                if (StringUtils.isNotEmpty(newMovie.getDirectorText())) {
                    existing.setDirectorText(newMovie.getDirectorText());
                }
                existing.setCurrentEpisode(newMovie.getCurrentEpisode());
                existing.setTotalEpisodes(newMovie.getTotalEpisodes());
                existing.setStatus(newMovie.getStatus());
            }
        }

        // Always update timestamp
        existing.setUpdateTime(DateUtils.getNowDate());
    }

    /**
     * Merge video resources based on update rule
     *
     * @param existingResources existing resources
     * @param newResources new resources
     * @param uprule update rule
     * @return merged resource list
     */
    public List<VideoResource> mergeVideoResources(List<VideoResource> existingResources,
                                                   List<VideoResource> newResources,
                                                   String uprule) {
        if (StringUtils.isEmpty(uprule)) {
            uprule = ",a"; // Default to append
        }

        String[] rules = uprule.split(",");
        for (String rule : rules) {
            if (StringUtils.isEmpty(rule)) {
                continue;
            }

            if (rule.startsWith("a")) {
                // Append: add new episodes only
                Map<String, VideoResource> existingMap = new HashMap<>();
                for (VideoResource resource : existingResources) {
                    String key = resource.getResources() + "_" + resource.getTitle();
                    existingMap.put(key, resource);
                }

                List<VideoResource> result = new ArrayList<>(existingResources);
                for (VideoResource newResource : newResources) {
                    String key = newResource.getResources() + "_" + newResource.getTitle();
                    if (!existingMap.containsKey(key)) {
                        result.add(newResource);
                    }
                }
                return result;
            }

            if (rule.startsWith("b")) {
                // Overwrite: replace all
                return newResources;
            }

            if (rule.startsWith("c")) {
                // Merge: update existing, add new
                Map<String, VideoResource> existingMap = new HashMap<>();
                for (VideoResource resource : existingResources) {
                    String key = resource.getResources() + "_" + resource.getTitle();
                    existingMap.put(key, resource);
                }

                List<VideoResource> result = new ArrayList<>();
                for (VideoResource newResource : newResources) {
                    String key = newResource.getResources() + "_" + newResource.getTitle();
                    VideoResource existing = existingMap.get(key);
                    if (existing != null) {
                        existing.setUrl(newResource.getUrl());
                        existing.setUpdateTime(DateUtils.getNowDate());
                        result.add(existing);
                        existingMap.remove(key);
                    } else {
                        result.add(newResource);
                    }
                }

                // Add remaining existing resources
                result.addAll(existingMap.values());
                return result;
            }

            if (rule.startsWith("d")) {
                // Skip: keep existing
                return existingResources;
            }
        }

        return existingResources;
    }
}